#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/kdev_t.h>
#include <linux/err.h>
#include <linux/compiler.h>
/*
 * @func: device open
 */
static int dev_open(struct inode *node, struct file *filep)
{
	printk(KERN_INFO "open device\n");
	return 0;
}

/*
 * @func: device read
 */
static ssize_t dev_read(struct file *filep, char __user *buffer, size_t size, loff_t *offset)
{
	printk(KERN_INFO "read device\n");
	return 0;
}

/*
 * @func: device write
 */
static ssize_t dev_write(struct file *filep, const char __user *buffer, size_t size, loff_t *offset)
{
	printk(KERN_INFO "write device\n");
	return 0;
}

/*
 * @func: device close
 */

static int dev_release(struct inode *node, struct file *filep)
{

	printk(KERN_INFO "release device\n");
	return 0;
}

struct mydev
{
	unsigned int 			major;
	char 					*dev_name;
	char 					*cls_name;
	char 					*cls_dev_name;
	struct class 			*cls;
	struct class_device 	*cls_dev;
	int 					flags;
	struct file_operations  dev_oper;
};

static struct mydev dev = {
    .major    = 111,
	.dev_name = "first_dev",        //cat /proc/devices 可以通过此名找打分配的主设备号
	.cls_name = "firstcls",         //创建目录：/sys/class/firstcls
	.cls_dev_name = "firstdev",     //创建目录：/sys/class/firstcls/firstdev , mdev会用这个名字创建设备节点名/dev/firstdev
	.cls = NULL,
	.cls_dev = NULL,
	.flags = 0,
	.dev_oper = {
		.owner		= THIS_MODULE,
		.open 		= dev_open,
		.read 		= dev_read,
		.write 		= dev_write,
		.release	= dev_release, 
	},
};

static int __init firstdrv_init(void)
{
    printk(KERN_INFO "The driver 'first_drv' is inserted!\n");
	//[0]. 注册一个字符设备
 	dev.major = register_chrdev(0, dev.dev_name, &dev.dev_oper);

    if(dev.major < 0)
	{
		printk(KERN_ERR "Register char device[%s] failed", dev.dev_name);
		goto ERR;
	}
	//[1]. 将字符设备信息注册到sys文件系统中
	dev.cls = class_create(THIS_MODULE, dev.cls_name);
	if(IS_ERR(dev.cls))
	{
		printk(KERN_ERR "Create class [%s] failed", dev.cls_name);
		unregister_chrdev(dev.major, dev.dev_name);
		goto ERR;
	}
	dev.cls_dev = class_device_create(dev.cls, NULL, MKDEV(dev.major, 0), NULL, dev.cls_dev_name);
	if(unlikely(IS_ERR(dev.cls_dev)))
	{
		printk(KERN_ERR "Create class device [%s] failed", dev.cls_dev_name);
		unregister_chrdev(dev.major, dev.dev_name);
		class_destroy(dev.cls);
		goto ERR;

	}
    return 0;
ERR:
    printk(KERN_ERR "The driver 'first_drv' register failed\n");
	dev.flags = -1;
	return -1;
}
static void __exit firstdrv_exit(void)
{
    printk(KERN_INFO "The driver 'first_drv' is removed!\n");
	if(!dev.flags)
	{
		unregister_chrdev(dev.major, dev.dev_name);
        class_device_unregister(dev.cls_dev);
		class_destroy(dev.cls);
	}
}



module_init(firstdrv_init);
module_exit(firstdrv_exit);


MODULE_LICENSE("GPL");

